iT邦幫忙

2024 iThome 鐵人賽

DAY 11
1
JavaScript

不會 VueUse 而被提分手的我系列 第 11

D-11 用 useCycleList 來做一個簡單的輪播吧 (carousel) — 從需求分析到未來優化

  • 分享至 

  • xImage
  •  

將 useCycleList 應用到一個簡單的輪播效果中,這就像一個永無止境的展示舞台,每一個畫面不斷切換,卻能有序而和諧地呈現。就像生活中的每一段經歷,總會輪流出現,無論是甜蜜還是苦澀,都有它存在的理由。我想,感情也是如此,像這輪播一樣,經歷過變化,最終會回到最初的美好。
https://ithelp.ithome.com.tw/upload/images/20240924/20162115lAc241RFzC.png

先上範例

點這裡玩玩看

https://ithelp.ithome.com.tw/upload/images/20240924/20162115Qu6Qgh0tjh.jpg

本篇將聚焦於需求開發流程。我們會先假設一個來自 PM 的需求,然後進行元件設計,接著進行簡單的初步測試,最後探討可能的優化方向。

來自 PM 的需求

我希望做一個能展示圖片的東西,讓使用者可以看圖片,圖片要能自己換,但也要能讓使用者自己點來切換。整體要感覺順暢、看起來舒服,然後不管在什麼裝置上都能用。使用時圖片不會卡住,感覺要自然流暢,還有當圖片還沒完全顯示時,也能有個提示讓人知道圖片在載入。

需求分析

根據需求描述,我們可以歸納出以下主要功能:

  1. 圖片輪播展示
  2. 上一張/下一張導航功能
  3. 輪播指示器
  4. 自動輪播
  5. 響應式設計
  6. 載入狀態處理

開發流程

1. 元件結構設計

我們將元件分為三個主要部分:

  • 圖片顯示區域
  • 導航按鈕
  • 輪播指示器(那些小圓點)

2. 狀態管理

使用 useCycleList 管理輪播狀態,包括:

  • 當前顯示的圖片
  • 切換至下一張或上一張圖片
  • 直接跳轉至指定圖片

3. 交互設計

  • 實現點擊導航按鈕以切換圖片
  • 實現點擊指示器以跳轉至對應圖片

4. 自動輪播

setInterval 來實現自動輪播功能,並在元件掛載時啟動此機制。

5. 樣式優化

利用 Tailwind CSS 類名實現:

  • 響應式佈局
  • 按鈕懸停效果
  • 圖片圓角和陰影

6. 過渡效果

用 Vue 的 transition 元件,為圖片切換添加淡入淡出效果

PM 沒提到,但感覺可以優化的功能

  1. 手勢支援:新增左右滑動功能以切換圖片,提升移動裝置使用體驗。
  2. 鍵盤導航:支援使用鍵盤左右方向鍵切換圖片,增強可訪問性。
  3. 自訂參數:將輪播間隔、轉場效果等參數化,便於根據需求調整。
  4. 延遲載入:僅預先載入當前及相鄰的圖片,以優化效能。
  5. 自適應高度:根據目前顯示的圖片自動調整輪播容器高度。
  6. 暫停功能:滑鼠懸停時暫停自動輪播。

原始碼

點這裡玩玩看

<template> 
  <div class="relative w-full max-w-2xl mx-auto">
    <!-- 輪播圖片 -->
    <div class="relative h-64 overflow-hidden rounded-lg shadow-lg">
      <transition name="fade" mode="out-in">
        <img
        v-if="state" 
          :key="state.id"
          :src="state.src"
          :alt="state.alt"
          class="absolute inset-0 w-full h-full object-cover"
        />
        <div v-else class="w-full h-full absolute">載入中...</div>
      </transition>
    </div>

    <!-- 導航按鈕 -->
    <div class="absolute inset-0 flex items-center justify-between p-4">
      <button
        @click="prev()"
        class="p-1 rounded-full shadow text-gray-800 bg-white bg-opacity-25 hover:bg-opacity-100"
      >
        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
        </svg>
      </button>
      <button
        @click="next()"
        class="p-1 rounded-full shadow text-gray-800  bg-white bg-opacity-25 hover:bg-opacity-100"
      >
        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
        </svg>
      </button>
    </div>

    <!-- 下面的圈圈 -->
    <div class="absolute bottom-4 left-0 right-0">
      <div class="flex items-center justify-center gap-2">
        <button
          v-for="(item, i) in images"
          :key="item.id"
          @click="go(i)"
          class="w-3 h-3 rounded-full transition-all bg-gray-300"
          :class="{
              'bg-white': index === i 
          }"
        />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">

import { ref, onMounted } from 'vue'
import { useCycleList } from '@vueuse/core'

const images = ref([
  { id: 1, src: 'https://picsum.photos/id/1018/800/400', alt: 'Misty mountains' },
  { id: 2, src: 'https://picsum.photos/id/1015/800/400', alt: 'River through the forest' },
  { id: 3, src: 'https://picsum.photos/id/1019/800/400', alt: 'Coastal sunrise' },
])

const { state, next, prev, go, index } = useCycleList(images)

// 自動輪播
const autoPlay = () => {
  const interval = setInterval(next, 5000)
  return () => clearInterval(interval)
}

// 在組件掛載時開始自動輪播
onMounted(autoPlay)

</script>

結論

我們可以發現,除了基本功能外,還有許多需要考慮的細節。這讓我想起經常聽到 PM 說:「什麼?這不是基本功能嗎?」每次聽到都讓我想吐血 (#`Д´)ノ

希望可以透過該元件的開發,讓各位簡單感受一下 vueuse 在實戰中的應用,幫這各位開發者在未來的某一天可以拿出來使用

好啦今天就到這邊~如果有任何錯誤都歡迎留言讓我知道喔 ヽ(●´∀`●)ノ


上一篇
D-10 useCycleList 解析與動機 — 解析循環的齒輪
下一篇
D-12 useAsyncState 文件說明與範例 — 解析取經的過程
系列文
不會 VueUse 而被提分手的我30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言